<?php

namespace App\Services\Tencent;

use Qcloud\Cos\Client;

class CosService
{
    private mixed $config;

    public function __construct()
    {
        $this->config = config('filesystems.disks.cos');
    }

    /**
     * 腾讯云预签名URL
     */
    public function getSignedUrl($dir = 'uploads/')
    {
        $ssl       = $this->config['ssl'] ? 'https' : 'http';//上传域名因存储区域不同而节点不同
        $secretId  = $this->config['secret_id'] ?? '';
        $secretKey = $this->config['secret_key'] ?? '';
        $bucket    = $this->config['bucket'] ?? '';
        $region    = $this->config['region'] ?? '';
        $time      = time();
//        $cosClient = new Client([
//            'region'      => $region,
//            'schema'      => $ssl, //协议头部，默认为http
//            'signHost'    => true, //默认签入Header Host；您也可以选择不签入Header Host，但可能导致请求失败或安全漏洞,若不签入host则填false
//            'credentials' => [
//                'secretId'  => $secretId,
//                'secretKey' => $secretKey
//            ]
//        ]);
        try {
//            $signedUrl = $cosClient->getPreSignedUrl('putObject', [
//                'Bucket'  => $bucket, //存储桶，格式：BucketName-APPID
//                'Key'     => $dir, //对象在存储桶中的位置，即对象键
//                'Body'    => 'string',
//                'Params'  => [], //http 请求参数，传入的请求参数需与实际请求相同，能够防止用户篡改此HTTP请求的参数,默认为空
//                'Headers' => [], //http 请求头部，传入的请求头部需包含在实际请求中，能够防止用户篡改签入此处的HTTP请求头部,默认已签入host
//            ], '+10 minutes'); //签名的有效时间

            //设置该policy超时时间是10s. 即这个policy过了这个有效时间，将不能访问。
            $addTime = 30 * 60;//三十分钟
            $expiration = $this->gmt_iso8601($time + $addTime);

            $StartTimestamp = $time;
            $EndTimestamp = $StartTimestamp + $addTime;
            $KeyTime = "$StartTimestamp;$EndTimestamp";

            $conditions = [
                ['content-length-range', 0, 1048576000],//最大文件大小.用户可以自己设置
                ["bucket" => $bucket],
                ["starts-with", '$key', $dir],// 表示用户上传的数据，必须是以$dir开始，不然上传会失败，这一步不是必须项，只是为了安全起见，防止用户通过policy上传到别人的目录。
                ["q-sign-algorithm" => "sha1"],
                ["q-ak" => $secretId],
                ["q-sign-time" => $KeyTime]
            ];
            $arr    = ['expiration' => $expiration, 'conditions' => $conditions];
            $policy = json_encode($arr);
            $policyBase64 = base64_encode($policy);

            // 签名
            $SignKey = hash_hmac('sha1', $KeyTime, $secretKey);
            $StringToSign = sha1($policy);
            $Signature = hash_hmac('sha1', $StringToSign, $SignKey);

            // 请求成功
            return [true, [
                'domain' => "{$bucket}.cos.{$region}.myqcloud.com",
                'ssl' => $ssl,
                'policy' => $policyBase64,
                'q_sign_algorithm' => 'sha1',
                'q_ak' => $secretId,
                'q_key_time' => $KeyTime,
                'q_signature' => $Signature,
            ]];
        } catch (\Exception $e) {
            return [false, $e->getMessage()];
        }
    }

    private function xml_parser($str)
    {
        $xml_parser = xml_parser_create();
        if (!xml_parse($xml_parser, $str, true)) {
            xml_parser_free($xml_parser);
            return $str;
        } else {
            $res = json_decode(json_encode(simplexml_load_string($str, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $res['Message'] ?? '请求错误';
        }
    }


    /**
     * 直接上传文件到腾讯云COS
     * @param \Illuminate\Http\UploadedFile $file 上传的文件对象
     * @param string $key 文件在COS中的路径
     * @param array $config COS配置
     * @return bool
     */
    public function uploadFile($file, $key, $config = [])
    {
        try {
            // 验证必要的配置参数
            $region = $config['region'] ?? $this->config['region'] ?? '';
            $secretId = $config['secret_id'] ?? $this->config['secret_id'] ?? '';
            $secretKey = $config['secret_key'] ?? $this->config['secret_key'] ?? '';
            $bucket = $config['bucket'] ?? $this->config['bucket'] ?? '';

            if (empty($region) || empty($secretId) || empty($secretKey) || empty($bucket)) {
                return false;
            }

            // 验证文件对象
            if (!$file || !$file->isValid()) {
                return false;
            }

            $cosClient = new Client([
                'region'      => $region,
                'schema'      => ($config['ssl'] ?? $this->config['ssl']) ? 'https' : 'http',
                'signHost'    => true,
                'credentials' => [
                    'secretId'  => $secretId,
                    'secretKey' => $secretKey
                ]
            ]);

            // 根据文件大小选择不同的上传方式
            $fileSize = $file->getSize();
            if ($fileSize > 10485760) { // 大于10MB使用流式上传
                $result = $cosClient->putObject([
                    'Bucket' => $bucket,
                    'Key'    => $key,
                    'Body'   => fopen($file->getRealPath(), 'r+'),
                ]);
            } else {
                $result = $cosClient->putObject([
                    'Bucket' => $bucket,
                    'Key'    => $key,
                    'Body'   => file_get_contents($file->getRealPath()),
                ]);
            }

            if (isset($result['ETag'])) {
                return true;
            } else {
                return false;
            }

        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * @param $time
     * @return string
     * @throws \Exception
     */
    private function gmt_iso8601($time)
    {
        $dtStr      = date("c", $time);
        $dateTime   = new \DateTime($dtStr);
        $expiration = $dateTime->format(\DateTime::ISO8601);
        $pos        = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);
        return $expiration . "Z";
    }
}